package com.thundern.tdcrawler.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.apache.http.HttpHost;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.thundern.tdcrawler.proxy.ProxyPool;
import com.thundern.tdcrawler.service.job.Job;

public class Site  {

	private long siteId;
	private String siteName;
	private String domain;//domain
	private String userAgent;
	private String startUrl;//should be unique
	private List<String> startUrls;//initBean
	private List<Request> startRequests /*= new ArrayList<Request>()*/;//initBean
	
	private Map<String, String> defaultCookies /*= new LinkedHashMap<String, String>()*/;//initBean
	private Table<String, String, String> cookies /*= HashBasedTable.create()*/;//initBean
	
	private String charset;	
	private int sleepTime = 5000;
    private int retryTimes = 0;
    private int cycleRetryTimes = 0;
    private int timeOut = 5000;
    private static final Set<Integer> DEFAULT_STATUS_CODE_SET = new HashSet<Integer>();
    private Set<Integer> acceptStatCode = DEFAULT_STATUS_CODE_SET;
    private Map<String, String> headers /*= new HashMap<String, String>()*/;//initBean
    private HttpHost httpProxy;
	private ProxyPool httpProxyPool /*= new ProxyPool()*/;//initBean
	
    private Job job;
	
    static {
        DEFAULT_STATUS_CODE_SET.add(200);
    }
    
    @PostConstruct
    public void initBean() {
    	defaultCookies = new LinkedHashMap<String, String>();
    	cookies = HashBasedTable.create();
    	headers = new HashMap<String, String>();
    	httpProxyPool=new ProxyPool();
    	startRequests = new ArrayList<Request>();
    	startRequests.add(new Request(startUrl));
    	
    	startUrls = new ArrayList<String>();
    	startUrls.add(startUrl);
    	
    	System.out.println(startUrl);
    	System.out.println(sleepTime);
    	System.out.println(charset);
    }
    
    private boolean useGzip = true;

    public Site(String startUrl) {
    	startRequests = new ArrayList<Request>();
    	startRequests.add(new Request(startUrl));
    }
    
    public Site() {
    }
    
    public Site(Request request) {
    	startRequests = new ArrayList<Request>();
    	startRequests.add(request);
    }
    
    public Site(List<Request>  startRequests) {    	
    	this.startRequests = startRequests;
    }
    
	public long getSiteId() {
		return siteId;
	}

	public void setSiteId(long siteId) {
		this.siteId = siteId;
	}

	public String getSiteName() {
		return siteName;
	}

	public void setSiteName(String siteName) {
		this.siteName = siteName;
	}

	public String getDomain() {
		return domain;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}

	public String getUserAgent() {
		return userAgent;
	}

	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}

	public String getStartUrl() {
		return startUrl;
	}

	public void setStartUrl(String startUrl) {
		this.startUrl = startUrl;
	}

	public List<String> getStartUrls() {
		return startUrls;
	}

	public void setStartUrls(List<String> startUrls) {
		this.startUrls = startUrls;
	}
	
	public List<Request> getStartRequests() {
		return startRequests;
	}

	public void setStartRequests(List<Request> startRequests) {
		this.startRequests = startRequests;
	}

	public Map<String, String> getCookies() {
		return defaultCookies;
	}

	public void setDefaultCookies(Map<String, String> defaultCookies) {
		this.defaultCookies = defaultCookies;
	}

	/**
     * Add a cookie with specific domain.
     *
     * @param domain
     * @param name
     * @param value
     * @return
     */
    public Site addCookie(String domain, String name, String value) {
        cookies.put(domain, name, value);
        return this;
    }
    
    public Map<String,Map<String, String>> getAllCookies() {
        return cookies.rowMap();
    }
    
	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public int getSleepTime() {
		return sleepTime;
	}

	public void setSleepTime(int sleepTime) {
		this.sleepTime = sleepTime;
	}

	public int getRetryTimes() {
		return retryTimes;
	}

	public void setRetryTimes(int retryTimes) {
		this.retryTimes = retryTimes;
	}

	public int getCycleRetryTimes() {
		return cycleRetryTimes;
	}

	public void setCycleRetryTimes(int cycleRetryTimes) {
		this.cycleRetryTimes = cycleRetryTimes;
	}

	public int getTimeOut() {
		return timeOut;
	}

	public void setTimeOut(int timeOut) {
		this.timeOut = timeOut;
	}

	public Set<Integer> getAcceptStatCode() {
		return acceptStatCode;
	}

	public void setAcceptStatCode(Set<Integer> acceptStatCode) {
		this.acceptStatCode = acceptStatCode;
	}

	public Map<String, String> getHeaders() {
		return headers;
	}

	public void setHeaders(Map<String, String> headers) {
		this.headers = headers;
	}

	public HttpHost getHttpProxy() {
		return httpProxy;
	}

	public void setHttpProxy(HttpHost httpProxy) {
		this.httpProxy = httpProxy;
	}

	public boolean isUseGzip() {
		return useGzip;
	}

	public void setUseGzip(boolean useGzip) {
		this.useGzip = useGzip;
	}
	
    public Job getJob() {
		return job;
	}

	public void setJob(Job job) {
		this.job = job;
	}

	@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Site site = (Site) o;

        if (cycleRetryTimes != site.cycleRetryTimes) return false;
        if (retryTimes != site.retryTimes) return false;
        if (sleepTime != site.sleepTime) return false;
        if (timeOut != site.timeOut) return false;
        if (acceptStatCode != null ? !acceptStatCode.equals(site.acceptStatCode) : site.acceptStatCode != null)
            return false;
        if (charset != null ? !charset.equals(site.charset) : site.charset != null) return false;
        if (defaultCookies != null ? !defaultCookies.equals(site.defaultCookies) : site.defaultCookies != null)
            return false;
        if (domain != null ? !domain.equals(site.domain) : site.domain != null) return false;
        if (headers != null ? !headers.equals(site.headers) : site.headers != null) return false;
        if (startRequests != null ? !startRequests.equals(site.startRequests) : site.startRequests != null)
            return false;
        if (userAgent != null ? !userAgent.equals(site.userAgent) : site.userAgent != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = domain != null ? domain.hashCode() : 0;
        result = 31 * result + (userAgent != null ? userAgent.hashCode() : 0);
        result = 31 * result + (defaultCookies != null ? defaultCookies.hashCode() : 0);
        result = 31 * result + (charset != null ? charset.hashCode() : 0);
        result = 31 * result + (startRequests != null ? startRequests.hashCode() : 0);
        result = 31 * result + sleepTime;
        result = 31 * result + retryTimes;
        result = 31 * result + cycleRetryTimes;
        result = 31 * result + timeOut;
        result = 31 * result + (acceptStatCode != null ? acceptStatCode.hashCode() : 0);
        result = 31 * result + (headers != null ? headers.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Site{" +
                "domain='" + domain + '\'' +
                ", userAgent='" + userAgent + '\'' +
                ", cookies=" + defaultCookies +
                ", charset='" + charset + '\'' +
                ", startRequests=" + startRequests +
                ", sleepTime=" + sleepTime +
                ", retryTimes=" + retryTimes +
                ", cycleRetryTimes=" + cycleRetryTimes +
                ", timeOut=" + timeOut +
                ", acceptStatCode=" + acceptStatCode +
                ", headers=" + headers +
                '}';
    }
    
    /**
     * Set httpProxyPool, String[0]:ip, String[1]:port <br>
     *
     * @return this
     */
	public Site setHttpProxyPool(List<String[]> httpProxyList) {
		this.httpProxyPool=new ProxyPool(httpProxyList);
		return this;
	}

	public ProxyPool getHttpProxyPool() {
		return httpProxyPool;
	}

	public HttpHost getHttpProxyFromPool() {
		return httpProxyPool.getProxy();
	}

	public void returnHttpProxyToPool(HttpHost proxy,int statusCode) {
		httpProxyPool.returnProxy(proxy,statusCode);
	}
	
	public Site setProxyReuseInterval(int reuseInterval) {
		this.httpProxyPool.setReuseInterval(reuseInterval);
		return this;
	}
}
